#include "Graphics/Vertex.hpp"

#include <cmath>
#include <sstream>

namespace Graph
{

float Vertex::sqrNorm() const
{
    return x * x + y * y + z * z;
}

float Vertex::norm() const
{
    return sqrt(sqrNorm());
}

Vertex& Vertex::normalize()
{
    return *this /= norm();
}

Vertex Vertex::normalized() const
{
    Vertex res = *this;
    return res /= norm();
}

Vertex& Vertex::operator *=(const float a)
{
    x *= a;
    y *= a;
    z *= a;
    return *this;
}

Vertex& Vertex::operator /=(const float a)
{
    x /= a;
    y /= a;
    z /= a;
    return *this;
}

Vertex& Vertex::operator +=(const Vertex &v)
{
    x += v.x;
    y += v.y;
    z += v.z;
    return *this;
}

Vertex& Vertex::operator -=(const Vertex &v)
{
    x -= v.x;
    y -= v.y;
    z -= v.z;
    return *this;
}

Vertex Vertex::vectorProduct(const Vertex &v) const
{
    return Vertex(y * v.z - z * v.y,
                  -x * v.z + z * v.x,
                  x * v.y - y * v.x);
}

Vertex Vertex::vectorProduct(const Vertex &v1, const Vertex &v2)
{
    return v1.vectorProduct(v2);
}

string Vertex::toString() const
{
    std::ostringstream sin;
    sin << "Vertex(" << x << ", " << y << ", " << z << ", rgba(" << color << "))";
    return sin.str();
}

/////////////////////////////////////////////////
/// ... Non member functions ...
/////////////////////////////////////////////////

Vertex operator +(const Vertex &v1, const Vertex &v2)
{
    Vertex res = v1;
    return res += v2;
}

Vertex operator -(const Vertex &v1, const Vertex &v2)
{
    Vertex res = v1;
    return res -= v2;
}

Vertex operator /(const Vertex &v, const float a)
{
    Vertex res = v;
    return res /= a;
}

Vertex operator *(const Vertex &v, const float a)
{
    Vertex res = v;
    return res *- a;
}

Vertex operator *(const float a, const Vertex &v)
{
    Vertex res = v;
    return res *- a;
}

float operator *(const Vertex &v1, const Vertex &v2)
{
    return sqrt(v1.x * v2.x + v1.y * v2.y + v1.z + v2.z);
}

}
